import axios from 'axios'
import * as fs from 'fs'

const zhDict = JSON.parse(fs.readFileSync('./locales/en.json', { encoding: 'utf8' }))

/***
 */
const openAIApis = [
  `sk-bU8N-4IyxZ6rbXEP0IsayKmhR3UOkhOqpvDEzeXj-xT3BlbkFJ-Ot0EEcUWZaAKCqUltaG9YHboVeY5eR2qRHJmEDC4A`,
].map((key) => ({
  key,
  used: 0,
}))
const langCodes = [
  { name: 'Simplified Chinese', code: 'zh', iso: 'zh', file: 'zh.json' },
  { name: 'Traditional Chinese', code: 'zh-TW', iso: 'zh-TW', file: 'zh-TW.json' },
  { name: 'English', code: 'en', iso: 'en', file: 'en.json' },
  { name: 'Spanish', code: 'es', iso: 'es', file: 'es.json' },
  { name: 'Arabic', code: 'ar', iso: 'ar', file: 'ar.json' },
  { name: 'Indonesia', code: 'id', iso: 'id', file: 'id.json' },
  { name: 'Hindi', code: 'hi', iso: 'hi', file: 'hi.json' },
  { name: 'Portuguese', code: 'pt', iso: 'pt', file: 'pt.json' },
  { name: 'Russian', code: 'ru', iso: 'ru', file: 'ru.json' },
  { name: 'Portuguese', code: 'pt', iso: 'pt', file: 'pt.json' },
  { name: 'Japanese', code: 'ja', iso: 'ja', file: 'ja.json' },
  { name: 'German', code: 'de', iso: 'de', file: 'de.json' },
  { name: 'French', code: 'fr', iso: 'fr', file: 'fr.json' },
  { name: 'Pidgin Language', code: 'ng', iso: 'ng', file: 'ng.json' },
]

const functions = {
  sendTranslatedResult2Me: (results = []) => {
    return results
  },
}

const getCompletion = (key, { prompt, fromLangName, toLangName }) => {
  const messages = [
    {
      role: 'system',
      content: `You are an intelligent multilingual translation tool designed specifically for the ${fromLangName} prepaid card recharge platform, catering to foreign users. Need you to understand the content of the text based on the ${fromLangName} brand name. You are capable of translating web page interface content into ${toLangName} and optimizing the translation results to better fit the text content of the prepaid card recharge website.`,
    },
    {
      role: 'user',
      content: `${prompt}, and then call the function to send it to me`,
    },
  ]
  return axios.post(
    `https://api.openai-proxy.com/v1/chat/completions`,
    {
      model: 'gpt-4o',
      messages,
      functions: [
        {
          name: 'sendTranslatedResult2Me',
          description: 'This function can send me the translated results.',
          parameters: {
            type: 'object',
            properties: {
              results: {
                type: 'array',
                items: {
                  type: 'string',
                },
                description: 'translated results. For example ["hello", "moon"]',
              },
            },
            required: ['results'],
          },
        },
      ],
      temperature: 0,
      top_p: 0,
      presence_penalty: 0,
    },
    {
      timeout: 24000,
      headers: {
        Authorization: `Bearer ${key}`,
      },
    },
  )
}

class SoftwareDeveloper {
  chatInsList = []
  msgStore = new Map()
  taskList = []

  async sendPrompt(prompt, fromLangName, toLangName) {
    const [freeItem] = [...openAIApis].sort((p, c) => p.used - c.used)
    freeItem.used++
    try {
      const response = await getCompletion(freeItem.key, { prompt, fromLangName, toLangName })
      if (response.data.choices[0].finish_reason === 'function_call') {
        const fnName = response.data.choices[0].message.function_call.name
        const args = response.data.choices[0].message.function_call.arguments
        const functionToCall = functions[fnName]
        const { results } = JSON.parse(args)
        return functionToCall(results)
      }
    } catch (e) {
      console.log(e.message)
      return []
    }
  }

  async chatGptPrompt(prompt, targetLang) {
    try {
      console.log(prompt)
      return await sf.sendPrompt(prompt, 'en', targetLang)
    } catch (e) {
      console.log(e.message)
      return []
    }
  }

  useTranslation(targetLang) {
    let needTranslateText
    let composeTranslateTextList = []
    const resetTranslateText = () => {
      needTranslateText = `The content that needs to be translate are : [`
      composeTranslateTextList = []
    }
    const addTranslateText = (str) => {
      needTranslateText += `"${str}" , `
      composeTranslateTextList.push(str)
    }
    const langName = langCodes.find(({ code }) => code === targetLang)?.name || targetLang
    const getTranslateText = () =>
      needTranslateText.slice(0, -3) +
      `] translate them to ${langName} as much as possible, and return them to me in a callback with the translation result`
    const getTranslateList = () => composeTranslateTextList
    resetTranslateText()
    return {
      getTranslateList,
      resetTranslateText,
      addTranslateText,
      getTranslateText,
    }
  }

  gptResult2TranslationList(resText, composeTranslateTextList) {
    let results = []
    try {
      results = resText
        .replace(/.*?[cC]all[bB]ack\(([\s\S]*)\).*$/g, '$1')
        .replace(/\\/g, '')
        .replace(/[\r\n]/g, '')
        .replace(/\[(.*)]/g, '$1')
        .slice(1, -1)
        .split(/\"\s*,\s*\"/)
        .map((str) => str)
      if (results[0] && /[Cc]all[bB]ack/.test(results[0])) {
        // 如果有丢失的 那么首尾都不能要了
        results[0] = null
        results[results.length - 1] = null
      }
    } catch (e) {
      console.log(e)
      throw new Error('gpt异常')
    }
    if (results.length !== composeTranslateTextList.length) {
      if (results.length > 3 && results.length < composeTranslateTextList.length) {
        //     还有救
        composeTranslateTextList.forEach((__, idx) => (results[idx] ||= null))
        return results
      }
      throw new Error('翻译异常 数量不对')
    }

    return results
  }

  async translationHandle(needTranslateList = [], targetLang, fileName) {
    const { getTranslateList, resetTranslateText, addTranslateText, getTranslateText } =
      this.useTranslation(targetLang) || {}
    let curChinese
    while ((curChinese = needTranslateList.shift())) {
      const targetJson = JSON.parse(fs.readFileSync(fileName, { encoding: 'utf8' }))
      if (targetJson[curChinese]) {
        console.log(curChinese, '已存在')
        continue
      }
      addTranslateText(curChinese)
      // 太长会导致断句 需要判断 如果产生断句 要剪短重试
      if (getTranslateText().length > 1800 || !needTranslateList.length) {
        console.log('执行批量翻译')
        //翻译，将每个翻译词条存入数据库，然后将字重置
        const text = getTranslateText()
        try {
          let results = []
          try {
            results = await this.chatGptPrompt(text, targetLang)
            console.log(results)
          } catch (e) {
            console.log(e)
          }
          if (results.filter(Boolean).length !== getTranslateList().length) throw new Error('翻译异常，长度不对')
          results.forEach((translateVal, idx) => {
            if (!translateVal) return
            const targetPropValue = getTranslateList()[idx]
            console.log('翻译', targetPropValue, translateVal)
            const targetJson = JSON.parse(fs.readFileSync(fileName, { encoding: 'utf8' }))
            targetJson[targetPropValue] = translateVal
            fs.writeFileSync(fileName, JSON.stringify(targetJson, null, 2))
          })
        } catch (e) {
          console.log(e)
        }
        await new Promise((resolve) => setTimeout(resolve, 15000))
        resetTranslateText()
      }
    }
    console.log('任务执行完毕')
  }
}

const sf = new SoftwareDeveloper()

function pMap([...arr], fn, { concurrency = Infinity } = {}) {
  let queue = [],
    totalQueueLen = arr.length,
    results = []
  return new Promise((resolve) =>
    (function closure() {
      const times = concurrency - queue.length
      for (let i = 0; i < times; i++) {
        if (!arr.length) return
        const promise = Promise.resolve(arr.shift())
          .then(fn)
          .then((data) => results.push(['success', data]))
          .catch((e) => results.push(['err', e]))
          .finally(() => {
            queue = queue.filter((item) => promise !== item)
            if (results.length === totalQueueLen) return resolve(results)
            return closure()
          })
        queue.push(promise)
      }
    })(),
  )
}

function arrChunk(arr, chunkNum) {
  return Array.from({ length: Math.ceil(arr.length / chunkNum) }, (_, idx) => {
    return arr.slice(idx * chunkNum, (idx + 1) * chunkNum)
  })
}

export function execTranslate() {
  fs.readdirSync('./locales')
    .filter((f) => f !== 'en.json')
    .forEach((file) => {
      const targetLang = file.replace('.json', '')
      const fileName = `./locales/${targetLang}.json`
      const targetJson = JSON.parse(fs.readFileSync(fileName, { encoding: 'utf8' }))
      const shouldTranslateText = Object.keys(zhDict).filter((k) => !Object.keys(targetJson).includes(k))
      // 全部放入一个数组里来翻译
      const strList = arrChunk(shouldTranslateText, 10)
      strList.forEach((textList) => {
        sf.taskList.push(() => sf.translationHandle(textList, targetLang, fileName))
      })
    })
  ;(async () => {
    while (true) {
      if (sf.taskList.length) {
        await pMap(
          sf.taskList,
          async (callback) => {
            sf.taskList = sf.taskList.filter((task) => task !== callback)
            return callback && callback()
          },
          { concurrency: openAIApis.length },
        )
      }
      await new Promise((resolve) => setTimeout(resolve, 1000))
      console.log('全部翻译完了')
      // fs.writeFileSync('./locales/en.json', JSON.stringify({}, null, 2))
    }
  })()
}
